<?php

namespace addons\shopro\service\pay;

use app\admin\model\shopro\commission\Agent;
use app\admin\model\shopro\commission\Level;
use app\admin\model\shopro\order\Order;
use app\admin\model\shopro\Pclog;
use app\admin\model\shopro\user\WalletLog;
use think\Log;
use app\admin\model\shopro\Pay as PayModel;
use app\admin\model\shopro\user\User;
use app\admin\model\shopro\order\Action;
use think\helper\Str;
use addons\shopro\service\Wallet as WalletService;


class PayOper
{
    protected $user = null;

    /**
     * 实例化
     *
     * @param mixed $user
     */
    public function __construct($user = null)
    {
        // 优先使用传入的用户
        $this->user = $user ? (is_numeric($user) ? User::get($user) : $user) : auth_user();
    }



    /**
     * 微信预付款
     *
     * @param think\Model $order
     * @param float $money
     * @param string $order_type
     * @return think\Model
     */
    public function wechat($order, $money, $order_type = 'order')
    {
        $pay = $this->addPay($order, [
            'order_type' => $order_type,
            'pay_type' => 'wechat',
            'pay_fee' => $money,
            'real_fee' => $money,
            'transaction_id' => null,
            'payment_json' => [],
            'status' => PayModel::PAY_STATUS_UNPAID
        ]);

        return $pay;
    }

    //新增 lina 工行支付 start
    /**
     * 工行支付
     *
     * @param think\Model $order
     * @param float $money
     * @param string $order_type
     * @return think\Model
     */
    public function icbc($order, $money, $order_type = 'order')
    {
        $pay = $this->addPay($order, [
            'order_type' => $order_type,
            'pay_type' => 'icbc',
            'pay_fee' => $money,
            'real_fee' => $money,
            'transaction_id' => null,
            'payment_json' => [],
            'status' => PayModel::PAY_STATUS_UNPAID
        ]);

        return $pay;
    }

    //新增 lina 工行支付 end

    /**
     * 支付宝预付款
     *
     * @param think\Model $order
     * @param float $money
     * @param string $order_type
     * @return think\Model
     */
    public function alipay($order, $money, $order_type = 'order')
    {
        $pay = $this->addPay($order, [
            'order_type' => $order_type,
            'pay_type' => 'alipay',
            'pay_fee' => $money,
            'real_fee' => $money,
            'transaction_id' => null,
            'payment_json' => [],
            'status' => PayModel::PAY_STATUS_UNPAID
        ]);

        return $pay;
    }



    /**
     * 余额付款
     *
     * @param think\Model $order
     * @param float $money
     * @param string $order_type
     * @return think\Model
     */
    public function money($order, $money, $order_type = 'order',$user_data=[])
    {
        // 余额支付金额，传入金额和剩余支付金额最大值
        $money = $order->remain_pay_fee > $money ? $money : $order->remain_pay_fee;     // 混合支付不能超过订单应支付总金额
        $memo="";
        $type='order_pay';
        if($order["type"]=="recharge_due" ){
            $memo="进/出货";
            $type='money_payment';
        }
        if($order["type"]=="payment_goods"){
            $memo="充值货款";
            $type='money_payment';
        }
        $user_data=empty($user_data)?$this->user:$user_data;
        $parent_user_id=WalletService::checkAellAgent($user_data["id"]);
        if(in_array($order["type"],["recharge_due","payment_goods"]) && empty($parent_user_id)){
            //没有出货上级
            $ext = $order->ext;
            $rule = $ext['rule'] ?? [];
            $pv_money = (isset($rule['money']) && $rule['money'] > 0) ? $rule['money'] : 0;
            Pclog::create([
                "order_id"=>$order["id"],
                "money"=>$money,
                "type"=>1,
                "pv_price"=>$pv_money,
                "ext"=>[
                    'order_id' => $order["id"],
                    'order_sn' => $order["order_sn"],
                    'order_type' => "money_payment",
                    'memo' => "充正",
                ],
                "user_id"=>$user_data["id"],
                "createtime"=>time(),
            ]);
        }
        // 扣除用户余额
        WalletService::change($user_data, 'money', -$money, $type, [
            'order_id' => $order->id,
            'order_sn' => $order->order_sn,
            //lina 修改 start
            //'order_type' => $order_type=="payment_goods"?"payment_goods_cut":$order_type,
            'order_type' => $order_type,
            //lina 修改 end
        ],$memo,$parent_user_id["id"]??0);

        // 添加支付记录
        $pay = $this->addPay($order, [
            'order_type' => $order_type,
            'pay_type' => 'money',
            'pay_fee' => $money,
            'real_fee' => $money,
            'transaction_id' => null,
            'payment_json' => [],
            'status' => PayModel::PAY_STATUS_PAID
        ],$user_data);

        // 余额直接支付成功，更新订单剩余应付款金额，并检测订单状态
        return $this->checkAndPaid($order, $order_type);
    }

    /**
     * 积分支付
     *
     * @param think\Model $order
     * @param float $money
     * @param string $order_type
     * @return think\Model
     */
    public function score($order, $score, $order_type = 'order')
    {
        if ($order_type == 'order') {
            if ($order['type'] == 'score') {
                $log_type = 'score_shop_pay';
                $real_fee = $score;         // 积分商城真实抵扣，就是积分
            } else {
                $log_type = 'order_pay';
                // $real_fee = ;         // 积分商城真实抵扣，就是积分
                error_stop('缺少积分抵扣金额');       // 支持积分抵扣时补全
            }
        }

        WalletService::change($this->user, 'score', -$score, $log_type, [
            'order_id' => $order->id,
            'order_sn' => $order->order_sn,
            'order_type' => $order_type,
        ]);

        // 添加支付记录
        $pay = $this->addPay($order, [
            'order_type' => $order_type,
            'pay_type' => 'score',
            'pay_fee' => $score,
            'real_fee' => $real_fee,
            'transaction_id' => null,
            'payment_json' => [],
            'status' => PayModel::PAY_STATUS_PAID
        ]);

        // 积分直接支付成功，更新订单剩余应付款金额，并检测订单状态
        return $this->checkAndPaid($order, $order_type);
    }


    /**
     * 线下支付(货到付款)
     *
     * @param think\Model $order
     * @param float $money
     * @param string $order_type
     * @return think\Model
     */
    public function offline($order, $money, $order_type = 'order')
    {
        // 添加支付记录
        $pay = $this->addPay($order, [
            'order_type' => $order_type,
            'pay_type' => 'offline',
            'pay_fee' => $money,
            'real_fee' => $money,
            'transaction_id' => null,
            'payment_json' => [],
            'status' => PayModel::PAY_STATUS_PAID
        ]);

        // 更新订单剩余应付款金额，并检测订单状态
        return $this->checkAndPaid($order, $order_type, 'offline');
    }


    /**
     * 微信支付宝支付回调通用方法
     *
     * @param \think\Model $pay
     * @param array $notify
     * @return void
     */
    public function notify($pay, $notify)
    {
        $pay->status = PayModel::PAY_STATUS_PAID;
        $pay->transaction_id = $notify['transaction_id'];
        $pay->buyer_info = $notify['buyer_info'];
        $pay->payment_json = $notify['payment_json'];
        $pay->paid_time = time();
        $pay->save();

        $orderModel = $this->getOrderModel($pay->order_type);
        $order = new $orderModel();
        $order = $order->where('id', $pay->order_id)->find();
        if (!$order) {
            // 订单未找到，非正常情况，这里记录日志
            Log::write('pay-notify-error:order notfound;pay:' . json_encode($pay) . ';notify:' . json_encode($notify));
            return false;
        }

        if ($order->status == $order::STATUS_UNPAID) {      // 未支付，检测支付状态
            $order = $this->checkAndPaid($order, $pay->order_type);
        }

        return $order;
    }

    /**
     * 查找出货上级
     * */
    public function checkAellAgent($user_id,$level=0)
    {
        $data=[];
        $user=User::with(['agent' => function ($query) {
            return $query->with('level_info');
        }])
            ->where(["id"=>$user_id])->find();//查找下单用户
        if(!empty($user["parent_user_id"])){
            $parent_user=User::with(['agent' => function ($query) {
                return $query->with('level_info');
            }])
                ->where(["id"=>$user["parent_user_id"]])->find();//查找下单用户上级
            if(!empty($parent_user)){
                // 扣除上级货款
                $parent_level=$parent_user["agent"]["level_info"]["level"]??0;
                $user_level=$user["agent"]["level_info"]["level"]??0;
                if($level>1){
                    $user_level=$level;
                }
                if(!empty($parent_level) && $parent_level>$user_level){
                    //上级等级高于下单用户等级
                    $data=$parent_user;
                }else{
                    return $this->checkAellAgent($parent_user["id"],$user_level);
                }
            }
        }
        return $data;
    }


    /**
     * 进/出货
     * */
    /*public function rechargePayment($user,$money,$order)
    {
        $momo="充值货款";
        if($order->type =='recharge_due') $momo="进/出货";
        $user_agnet=User::with(['agent' => function ($query) {
            return $query->with('level_info');
        }])
            ->where(["id"=>$user["id"]])->find();//查找下单用户
        WalletService::changePayment($user, 'payment_goods', $money, 'payment_goods_add', [
            'order_id' => $order->id,
            'order_sn' => $order->order_sn,
            'order_type' => 'payment_goods',
        ],$momo,$user_agnet["parent_user_id"]);
        if(!empty($user_agnet["parent_user_id"])){
            //用户上级不为空
            $parent_user=$this->checkAellAgent($user["id"]);
            if(!empty($parent_user)){
                $parent_user=User::with(['agent' => function ($query) {
                    return $query->with('level_info');
                }])
                    ->where(["id"=>$parent_user["id"]])->find();//查找下单用户上级
                //dump($parent_user);die();
                $rate=$parent_user["agent"]["level_info"]["commission_rules"]["commission_1"]??40;//上级实际增加成本
                $parent_money=(bcmul($money,($rate/100)));//上级余额成本
                //出货上级扣除货款
                WalletService::changePayment($parent_user["id"], 'payment_goods',-$money, 'payment_goods_cut', [
                    'order_id' => $order->id,
                    'order_sn' => $order->order_sn,
                    'order_type' => "payment_goods_cut",
                ],'来自'.$user["nickname"].'['.$user_agnet["agent"]["level_info"]['name'].']'.$momo);
                //增加余额成本
                //money_payment=充值货款,money_payment_cost=充值货款成本价,money_payment_income=充值货款收益,
                //money_payment_cut_income=充值货款收益支出平级奖,money_payment_cut_payment=充值货款收益支出充值货款
                WalletService::changePayment($parent_user["id"], 'money',$parent_money, 'money_payment_cost', [
                    'order_id' => $order->id,
                    'order_sn' => $order->order_sn,
                    'order_type' => "money_payment_cost",
                ],'来自'.$user["nickname"].'['.$user_agnet["agent"]["level_info"]['name'].']'.$momo."成本");
                //增加余额收益
                $commiss=bcsub($order["order_amount"],$parent_money);//收益
                WalletService::changePayment($parent_user["id"], 'money',$commiss, 'money_payment_income', [
                    'order_id' => $order->id,
                    'order_sn' => $order->order_sn,
                    'order_type' => "money_payment_income",
                ],'来自'.$user["nickname"].'['.$user_agnet["agent"]["level_info"]['name'].']'.$momo."收益");
                $pj_money=0;
                if($parent_user["id"]!=$user["parent_user_id"]){
                    //如果出货上级不是推荐上级
                    $pj_money=bcmul($commiss,0.2,2);//平级奖励
                    //扣除出货上级平级奖励
                    WalletService::changePayment($parent_user["id"], 'money',-$pj_money, 'money_payment_cut_income', [
                        'order_id' => $order->id,
                        'order_sn' => $order->order_sn,
                        'order_type' => "money_payment_cut_income",
                    ],"扣除平级奖励");
                    //2024--1-10  修改前-进货人上级拿平级奖   修改后-进货人上级关系链中等级和进货人一致的用户拿平级奖
                    $sideways=WalletService::findSideways($user["parent_user_id"],$user["agent"]["level"]);
                    if(!empty($sideways)){
                        WalletService::changePayment($sideways, 'money',$pj_money, 'money_payment_cut_income', [
                            'order_id' => $order["id"],
                            'order_sn' => $order["order_sn"],
                            'order_type' => "money_payment_cut_income",
                        ],"平级奖励");
                    }
                }
                }
                else{
                    //平台
                    $level=Level::order("level","desc")->limit(2)->select();
                    $ratio=0;
                    if(!empty($level)){
                        if(!empty($level[1]["commission_rules"]["commission_1"]) && !empty($level[0]["commission_rules"]["commission_1"])){
                            $ratio=bcsub($level[1]["commission_rules"]["commission_1"],$level[0]["commission_rules"]["commission_1"],2);
                        }
                }
                if($ratio>0){
                    //pv*(（倒数第二等级-最高等级）/100)*0.2
                    $pv_money=bcmul($money,($ratio/100));
                    //2024--1-10  修改前-进货人上级拿平级奖   修改后-进货人上级关系链中等级和进货人一致的用户拿平级奖
                    $sideways=WalletService::findSideways($user["parent_user_id"],$user["agent"]["level"]);
                    if(!empty($sideways)){
                        WalletService::changePayment($sideways, 'money',$pj_money, 'money_payment_cut_income', [
                            'order_id' => $order["id"],
                            'order_sn' => $order["order_sn"],
                            'order_type' => "money_payment_cut_income",
                        ],"平级奖励");
                    }
                }
            }
        }
    }*/
    /**
     * 更新订单剩余应支付金额，并且检测订单状态
     *
     * @param think\Model $order
     * @param string $order_type
     * @return think\Model
     */
    public function checkAndPaid($order, $order_type, $pay_mode = 'online')
    {
        // 获取订单已支付金额
        //$payed_fee = $this->getPayedFee($order, $order_type);
        if($order_type=="recharge_due"){
            $payed_fee = 0;
        }else{
            $payed_fee = $this->getPayedFee($order, $order_type);
        }

        $remain_pay_fee = bcsub($order->pay_fee, (string)$payed_fee, 2);

        $order->remain_pay_fee = $remain_pay_fee;
        if ($remain_pay_fee <= 0) {
            $order->remain_pay_fee = 0;
            $order->paid_time = time();
            $order->status = $order::STATUS_PAID;
        } else {
            if ($pay_mode == 'offline') {
                // 订单未支付成功，并且是线下支付(货到付款)，将订单状态改为 pending
                $order->status = $order::STATUS_PENDING;
                $order->ext = array_merge($order->ext, ['pending_time' => time()]);     // 货到付款下单时间
                $order->pay_mode = 'offline';
            }
        }
        if($order["type"]=="recharge_due"){
            $ext = $order->ext;
            $rule = $ext['rule'] ?? [];
            $money = (isset($rule['money']) && $rule['money'] > 0) ? $rule['money'] : 0;
            if ($money > 0) {
                // 货款进/出货
                $user = User::get($order->user_id);
                WalletService::rechargePayment($user,$money,$order);
                /*$parent_user_id=WalletService::checkAellAgent($user);
                WalletLog::where(["type"=>"money","event"=>"money_payment","order_id"=>$order["id"],"user_id"=>$order["user_id"]])
                    ->update(["flow_id"=>$parent_user_id["id"]??0]);*/
                //$this->rechargePayment($user,$money,$order);
            }
            return $order;
        }
        //dump(11);die();

        /*dump($order);die();

        $order = Order::with('items')->fetchSql()->where('id', $order['id'])->find();
        dump($order);die();*/
        /*$user = User::get($order->user_id);
        // 触发订单支付完成事件
        $data = ['order' => $order, 'user' => $user];
        $ext = $order->ext;
        $rule = $ext['rule'] ?? [];
        $money = (isset($rule['money']) && $rule['money'] > 0) ? $rule['money'] : 0;
        $this->rechargePayment($user,$money,$order);
        dump(11);die();*/
        $order->save();

        if ($order->status == $order::STATUS_PAID) {
            // 订单支付完成
            $user = User::where('id', $order->user_id)->find();
            if ($order_type == 'order') {
                if ($pay_mode == 'offline') {
                    Action::add($order, null, auth_admin(), 'admin', '管理员操作自动货到付款支付成功');
                    // 在控制器执行后续内容，这里不再处理
                    return $order;
                } else {
                    Action::add($order, null, $user, 'user', '用户支付成功');
                    // 支付成功后续使用异步队列处理
                    \think\Queue::push('\addons\shopro\job\OrderPaid@paid', ['order' => $order, 'user' => $user], 'shopro-high');
                }
            } else if ($order_type == 'trade_order' || $order_type=='recharge_due') {
                // 支付成功后续使用异步队列处理
                \think\Queue::push('\addons\shopro\job\trade\OrderPaid@paid', ['order' => $order, 'user' => $user], 'shopro-high');
            }
        } else if ($order->status == $order::STATUS_PENDING) {
            // 货到付款，添加货到付款队列（后续也需要处理拼团， 减库存等等）
            $user = User::where('id', $order->user_id)->find();
            if ($order_type == 'order') {
                Action::add($order, null, $user, 'user', '用户货到付款下单成功');

                // 支付成功后续使用异步队列处理
                \think\Queue::push('\addons\shopro\job\OrderPaid@offline', ['order' => $order, 'user' => $user], 'shopro-high');
            }
        }

        return $order;
    }



    /**
     * 获取订单已支付金额，商城订单 计算 积分抵扣金额
     *
     * @param \think\Model $order
     * @param string $order_type
     * @return string
     */
    public function getPayedFee($order, $order_type)
    {
        // 锁定读取所有已支付的记录，判断已支付金额
        $pays = PayModel::{'type' . Str::studly($order_type)}()->paid()->where('order_id', $order->id)->lock(true)->select();
        // 商城或者积分商城订单
        $payed_fee = '0';
        foreach ($pays as $key => $pay) {
            if ($pay->pay_type == 'score') {
                if ($order_type == 'order' && $order['type'] == 'goods') {
                    // 商城类型订单，并且不是积分商城订单，加上积分抵扣真实金额
                    $payed_fee = bcadd($payed_fee, $pay->real_fee, 2);
                } else {
                    // 其他类型，需要计算积分抵扣的金额时
                }
            } else {
                $payed_fee = bcadd($payed_fee, $pay->real_fee, 2);
            }
        }

        return $payed_fee;
    }



    /**
     * 获取剩余可退款的pays 记录（不含积分抵扣）
     *
     * @param integer $order_id
     * @param string $sort  排序：money=优先退回余额支付的钱
     * @return \think\Collection
     */
    public function getCanRefundPays($order_id, $sort = 'money')
    {
        // 商城订单，已支付的 pay 记录, 这里只查 钱的支付记录，不查积分
        $pays = PayModel::typeOrder()->paid()->isMoney()->where('order_id', $order_id)->lock(true)->order('id', 'asc')->select();
        $pays = collection($pays);
        if ($sort == 'money') {
            // 对 pays 进行排序，优先退 money 的钱
            $pays = $pays->sort(function ($a, $b) {
                if ($a['pay_type'] == 'money' && $b['pay_type'] == 'money') {
                    return 0;
                } else if ($a['pay_type'] == 'money' && $b['pay_type'] != 'money') {
                    return -1;
                } else if ($a['pay_type'] != 'money' && $b['pay_type'] == 'money') {
                    return 1;
                } else {
                    return 0;
                }
            });

            $pays = $pays->values();
        }

        return $pays;
    }



    /**
     * 获取剩余可退款金额，不含积分相关支付
     *
     * @param mixed $pays
     * @return string
     */
    public function getRemainRefundMoney($pays)
    {
        // 拿到 所有可退款的支付记录
        $pays = ($pays instanceof \think\Collection) ? $pays : $this->getCanRefundPays($pays);

        // 支付金额，除了已经退完款的金额 （这里不退积分）
        $payed_money = (string)array_sum($pays->column('pay_fee'));
        // 已经退款金额 （这里不退积分）
        $refunded_money = (string)array_sum($pays->column('refund_fee'));
        // 当前剩余的最大可退款金额，支付金额 - 已退款金额
        $remain_max_refund_money = bcsub($payed_money, $refunded_money, 2);

        return $remain_max_refund_money;
    }



    /**
     * 添加 pay 记录
     *
     * @param think\Model $order
     * @param array $params
     * @return think\Model
     */
    public function addPay($order, $params,$user=[])
    {
        $payModel = new PayModel();
        $user["id"]=$user["id"]??$order["user_id"];
        $payModel->order_type = $params['order_type'];
        $payModel->order_id = $order->id;
        $payModel->pay_sn = get_sn($user["id"], 'P');
        $payModel->user_id = $user["id"];
        $payModel->pay_type = $params['pay_type'];
        $payModel->pay_fee = $params['pay_fee'];
        $payModel->real_fee = $params['real_fee'];
        $payModel->transaction_id = $params['transaction_id'];
        $payModel->payment_json = $params['payment_json'];
        $payModel->paid_time = $params['status'] == PayModel::PAY_STATUS_PAID ? time() : null;
        $payModel->status = $params['status'];
        $payModel->refund_fee = 0;
        $payModel->save();

        return $payModel;
    }


    public function getOrderModel($order_type)
    {
        switch ($order_type) {
            case 'trade_order':
                $orderModel = '\\app\\admin\\model\\shopro\\trade\\Order';
                break;
            case 'order':
                $orderModel = '\\app\\admin\\model\\shopro\\order\\Order';
                break;
            default:
                $orderModel = '\\app\\admin\\model\\shopro\\order\\Order';
                break;
        }

        return $orderModel;
    }
}
